<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="RZ0KP" id="RZ0KP"><span data-lake-id="ue844bc08" id="ue844bc08">典型回答</span></h1>
  <p data-lake-id="u8d517b60" id="u8d517b60"><br></p>
  <p data-lake-id="ud4504521" id="ud4504521"><span data-lake-id="u616b93f6" id="u616b93f6">如果不能使用synchronized和lock的话，想要实现单例可以通过饿汉模式、枚举、以及静态内部类的方式实现。</span></p>
  <p data-lake-id="u979b96bb" id="u979b96bb"><br></p>
  <p data-lake-id="u9f70581e" id="u9f70581e"><strong><span data-lake-id="uc05aa84d" id="uc05aa84d">饿汉</span></strong><span data-lake-id="u153584f5" id="u153584f5">，其实都是通过定义静态的成员变量，以保证instance可以在类初始化的时候被实例化。</span></p>
  <p data-lake-id="u3bd3f451" id="u3bd3f451"><span data-lake-id="u5da1fcfd" id="u5da1fcfd">​</span><br></p>
  <p data-lake-id="u1fad4908" id="u1fad4908"><strong><span data-lake-id="uc537635f" id="uc537635f">静态内部类</span></strong><span data-lake-id="uede50bb2" id="uede50bb2">，这种方式和饿汉方式只有细微差别，只是做法上稍微优雅一点。这种方式是Singleton类被装载了，instance不一定被初始化。因为SingletonHolder类没有被主动使用，只有显示通过调用getInstance方法时，才会显示装载SingletonHolder类，从而实例化instance。。。但是，原理和饿汉一样。</span></p>
  <p data-lake-id="u29bd9963" id="u29bd9963"><span data-lake-id="u1428869e" id="u1428869e">​</span><br></p>
  <p data-lake-id="u1e3239b0" id="u1e3239b0"><strong><span data-lake-id="uc44fa2d6" id="uc44fa2d6">枚举</span></strong><span data-lake-id="u11565640" id="u11565640">，其实，如果把枚举类进行反编译，你会发现他也是使用了static final来修饰每一个枚举项。</span></p>
  <p data-lake-id="u651018bd" id="u651018bd"><span data-lake-id="u6bb08e95" id="u6bb08e95">​</span><br></p>
  <p data-lake-id="ua3367a17" id="ua3367a17"><span data-lake-id="u261880c8" id="u261880c8">其实，上面三种方式，都是依赖静态数据在类初始化的过程中被实例化这一机制的。但是，如果真要较真的话，ClassLoader的loadClass方法在加载类的时候使用了synchronized关键字。也正是因为这样， 除非被重写，这个方法默认在整个装载过程中都是同步的（线程安全的）。</span></p>
  <p data-lake-id="u3880a7bc" id="u3880a7bc"><span data-lake-id="u97014ca6" id="u97014ca6">​</span><br></p>
  <p data-lake-id="ub04d436e" id="ub04d436e"><span data-lake-id="u5915c87d" id="u5915c87d">那么，除了上面这三种，还有一种无锁的实现方式，那就是CAS。</span></p>
  <p data-lake-id="u19e446ac" id="u19e446ac"><span data-lake-id="u62c78a00" id="u62c78a00">​</span><br></p>
  <h1 data-lake-id="Dcu29" id="Dcu29"><span data-lake-id="ufa560390" id="ufa560390">扩展知识</span></h1>
  <p data-lake-id="ueb29f4cf" id="ueb29f4cf"><br></p>
  <h2 data-lake-id="aBgGj" id="aBgGj"><span data-lake-id="ud78f0708" id="ud78f0708">CAS实现线程安全的单例</span></h2>
  <p data-lake-id="u6da3a19c" id="u6da3a19c"><br></p>
  <pre lang="java"><code>
public class Singleton {
    private static final AtomicReference&lt;Singleton&gt; INSTANCE = new AtomicReference&lt;Singleton&gt;(); 

    private Singleton() {}

    public static Singleton getInstance() {
        for (;;) {
            Singleton singleton = INSTANCE.get();
            if (null != singleton) {
                return singleton;
            }

            singleton = new Singleton();
            if (INSTANCE.compareAndSet(null, singleton)) {
                return singleton;
            }
        }
    }
}
</code></pre>
  <p data-lake-id="ud3348ab6" id="ud3348ab6"><span data-lake-id="u3f8508e8" id="u3f8508e8">​</span><br></p>
  <p data-lake-id="u4054c4b2" id="u4054c4b2"><span data-lake-id="uc53fb381" id="uc53fb381">用CAS的好处在于不需要使用传统的锁机制来保证线程安全。</span></p>
  <p data-lake-id="u55a09338" id="u55a09338"><span data-lake-id="u92d7f35c" id="u92d7f35c"><br></span><span data-lake-id="uaf26d75a" id="uaf26d75a">但是我们的实现方式中，用了一个for循环一直在进行重试，所以，这种方式有一个比较大的缺点在于，如果忙等待一直执行不成功(一直在死循环中)，会对CPU造成较大的执行开销。</span></p>
  <p data-lake-id="ucd8ff3ec" id="ucd8ff3ec"><span data-lake-id="u4053e527" id="u4053e527"><br><br></span></p>
 </body>
</html>